package robot

import (
	"context"
	"strconv"
	"time"

	"device-admin/config/redis"
	"device-admin/internal/app/grpc/protoc/robotc"
	alarm_monitor "device-admin/internal/app/grpc/service/alarm_monitor"
	"device-admin/internal/app/web/service/alarm"
	"device-admin/internal/define"
	"device-admin/internal/models"

	"192.168.1.75/go-pkg/go-cache"
	"google.golang.org/protobuf/proto"
)

// 告警配置
var AlarmSetConfig *robotc.AlarmSetConfig

// init 告警变量初始化
func init() {
	// 初始化95告警
	alarmSetConfigConditionBase := &robotc.AlarmSetConfigConditionBase{
		Valid:            1,
		StartHour:        0,
		StartMin:         0,
		EndHour:          23,
		EndMin:           59,
		NotifyAlarmCount: 1,
		Account: &robotc.AccountMsg{
			UserName: []byte("admin"),
			UserID:   []byte("1"),
		},
	}
	// 嵌入式告警
	alarmSetConfigConditionBase.AlarmType = 8
	alarmSetConfigConditionEmbError := &robotc.AlarmSetConfigConditionEmbError{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      1,
	}
	alarmSetConfigConditionEmbErrorBytes, _ := proto.Marshal(alarmSetConfigConditionEmbError)
	// 超声告警 15*60
	alarmSetConfigConditionBase.AlarmType = 0
	alarmSetConfigConditionUltrasound := &robotc.AlarmSetConfigConditionUltrasound{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	alarmSetConfigConditionUltrasoundBytes, _ := proto.Marshal(alarmSetConfigConditionUltrasound)
	// 里程计[停止移动] 15*60
	alarmSetConfigConditionBase.AlarmType = 4
	alarmSetConfigConditionCurrOdometer := &robotc.AlarmSetConfigConditionCurrOdometer{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	alarmSetConfigConditionCurrOdometerBytes, _ := proto.Marshal(alarmSetConfigConditionCurrOdometer)

	// 碰撞告警 10*60
	alarmSetConfigConditionBase.AlarmType = 1
	alarmSetConfigConditionAntiCollision := &robotc.AlarmSetConfigConditionAntiCollision{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      5 * 60,
	}
	alarmSetConfigConditionAntiCollisionBytes, _ := proto.Marshal(alarmSetConfigConditionAntiCollision)
	// 待机告警 15*60
	alarmSetConfigConditionBase.AlarmType = 9
	AlarmSetConfigConditionIdling := &robotc.AlarmSetConfigConditionIdling{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	AlarmSetConfigConditionIdlingBytes, _ := proto.Marshal(AlarmSetConfigConditionIdling)
	// 单线雷达停止移动 15*60
	alarmSetConfigConditionBase.AlarmType = 15
	alarmSetConfigConditionAlgorithmSingleradar := &robotc.AlarmSetConfigConditionAlgorithmSingleradar{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	alarmSetConfigConditionAlgorithmSingleradarBytes, _ := proto.Marshal(alarmSetConfigConditionAlgorithmSingleradar)
	// 多线雷达停止移动 15*60
	alarmSetConfigConditionBase.AlarmType = 16
	alarmSetConfigConditionAlgorithmMultiradar := &robotc.AlarmSetConfigConditionAlgorithmMultiradar{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	alarmSetConfigConditionAlgorithmMultiradarBytes, _ := proto.Marshal(alarmSetConfigConditionAlgorithmMultiradar)
	// 虚拟墙停止移动 10*60
	alarmSetConfigConditionBase.AlarmType = 17
	alarmSetConfigConditionAlgorithmVirtualwall := &robotc.AlarmSetConfigConditionAlgorithmVirtualwall{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      10 * 60,
	}
	alarmSetConfigConditionAlgorithmVirtualwallBytes, _ := proto.Marshal(alarmSetConfigConditionAlgorithmVirtualwall)
	// RGBD停止移动 10*60
	alarmSetConfigConditionBase.AlarmType = 18
	alarmSetConfigConditionAlgorithmRGBD := &robotc.AlarmSetConfigConditionAlgorithmRGBD{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	alarmSetConfigConditionAlgorithmRGBDBytes, _ := proto.Marshal(alarmSetConfigConditionAlgorithmRGBD)
	// 急停告警 15*60
	alarmSetConfigConditionBase.AlarmType = 5
	alarmSetConfigConditionEmergencyStop := &robotc.AlarmSetConfigConditionEmergencyStop{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	alarmSetConfigConditionEmergencyStopBytes, _ := proto.Marshal(alarmSetConfigConditionEmergencyStop)
	// 急停未复位 15*60
	alarmSetConfigConditionBase.AlarmType = 24
	alarmSetConfigConditionEmergencyStopResetkey := &robotc.AlarmSetConfigConditionEmergencyStopResetkey{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	alarmSetConfigConditionEmergencyStopResetkeyBytes, _ := proto.Marshal(alarmSetConfigConditionEmergencyStopResetkey)
	// 命令暂停 15*60
	alarmSetConfigConditionBase.AlarmType = 19
	alarmSetConfigConditionReqPausePeople := &robotc.AlarmSetConfigConditionReqPausePeople{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	alarmSetConfigConditionReqPausePeopleBytes, _ := proto.Marshal(alarmSetConfigConditionReqPausePeople)
	// 识别人体 15*60
	alarmSetConfigConditionBase.AlarmType = 20
	alarmSetConfigConditionReqPauseAiServerHuman := &robotc.AlarmSetConfigConditionReqPauseAiServerHuman{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	alarmSetConfigConditionReqPauseAiServerHumanBytes, _ := proto.Marshal(alarmSetConfigConditionReqPauseAiServerHuman)
	// 售卖暂停 15*60
	alarmSetConfigConditionBase.AlarmType = 21
	alarmSetConfigConditionReqPauseAiServerSell := &robotc.AlarmSetConfigConditionReqPauseAiServerSell{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	alarmSetConfigConditionReqPauseAiServerSellBytes, _ := proto.Marshal(alarmSetConfigConditionReqPauseAiServerSell)
	// 算法围困 10*60
	alarmSetConfigConditionBase.AlarmType = 6
	alarmSetConfigConditionSIEGE := &robotc.AlarmSetConfigConditionSIEGE{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      10 * 60,
	}
	alarmSetConfigConditionSIEGEBytes, _ := proto.Marshal(alarmSetConfigConditionSIEGE)
	// 雷达遮挡 10*60
	alarmSetConfigConditionBase.AlarmType = 12
	alarmSetConfigConditionRadarOcclusion := &robotc.AlarmSetConfigConditionRadarOcclusion{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	alarmSetConfigConditionRadarOcclusionBytes, _ := proto.Marshal(alarmSetConfigConditionRadarOcclusion)
	// 强制转动
	alarmSetConfigConditionBase.AlarmType = 13
	alarmSetConfigConditionForcedTurn := &robotc.AlarmSetConfigConditionForcedTurn{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      1,
	}
	alarmSetConfigConditionForcedTurnBytes, _ := proto.Marshal(alarmSetConfigConditionForcedTurn)
	// 无定位 15*60
	alarmSetConfigConditionBase.AlarmType = 22
	alarmSetConfigConditionPositionStatic := &robotc.AlarmSetConfigConditionPositionStatic{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      15 * 60,
	}
	alarmSetConfigConditionPositionStaticBytes, _ := proto.Marshal(alarmSetConfigConditionPositionStatic)
	// 电梯告警 5*60
	alarmSetConfigConditionBase.AlarmType = 11
	alarmSetConfigConditionElevator := &robotc.AlarmSetConfigConditionElevator{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      5 * 60,
	}
	alarmSetConfigConditionElevatorBytes, _ := proto.Marshal(alarmSetConfigConditionElevator)
	// 低电告警 10%，10*60
	alarmSetConfigConditionBase.AlarmType = 10
	alarmSetConfigConditionLowBatt := &robotc.AlarmSetConfigConditionLowBatt{
		BaseCondition: alarmSetConfigConditionBase,
		LowBatt:       10,
		Duration:      10 * 60,
	}
	alarmSetConfigConditionLowBattBytes, _ := proto.Marshal(alarmSetConfigConditionLowBatt)
	// 定位丢失 10*60
	alarmSetConfigConditionBase.AlarmType = 14
	alarmSetConfigConditionLossOfPositioning := &robotc.AlarmSetConfigConditionLossOfPositioning{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      10 * 60,
	}
	alarmSetConfigConditionLossOfPositioningBytes, _ := proto.Marshal(alarmSetConfigConditionLossOfPositioning)
	// 对桩告警/回充失败 10*60
	alarmSetConfigConditionBase.AlarmType = 7
	alarmSetConfigConditionBackCharge := &robotc.AlarmSetConfigConditionBackCharge{
		BaseCondition: alarmSetConfigConditionBase,
		FailuresNum:   5,
	}
	alarmSetConfigConditionBackChargeBytes, _ := proto.Marshal(alarmSetConfigConditionBackCharge)
	// 断充告警 bool
	alarmSetConfigConditionBase.AlarmType = 23
	alarmSetConfigConditionStopChargingException := &robotc.AlarmSetConfigConditionStopChargingException{
		BaseCondition: alarmSetConfigConditionBase,
		Duration:      1,
	}
	alarmSetConfigConditionStopChargingExceptionBytes, _ := proto.Marshal(alarmSetConfigConditionStopChargingException)
	AlarmSetConfig = &robotc.AlarmSetConfig{}
	AlarmSetConfig.AlarmSet = append(AlarmSetConfig.AlarmSet,
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 嵌入式
			AlarmConfigType: string(alarmSetConfigConditionEmbError.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionEmbErrorBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 超声告警
			AlarmConfigType: string(alarmSetConfigConditionUltrasound.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionUltrasoundBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 碰撞告警
			AlarmConfigType: string(alarmSetConfigConditionAntiCollision.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionAntiCollisionBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 停止移动[里程计]
			AlarmConfigType: string(alarmSetConfigConditionCurrOdometer.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionCurrOdometerBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 待机告警
			AlarmConfigType: string(AlarmSetConfigConditionIdling.ProtoReflect().Descriptor().FullName()),
			BodyContent:     AlarmSetConfigConditionIdlingBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 单线雷达
			AlarmConfigType: string(alarmSetConfigConditionAlgorithmSingleradar.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionAlgorithmSingleradarBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 多线雷达
			AlarmConfigType: string(alarmSetConfigConditionAlgorithmMultiradar.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionAlgorithmMultiradarBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 虚拟墙
			AlarmConfigType: string(alarmSetConfigConditionAlgorithmVirtualwall.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionAlgorithmVirtualwallBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // RGBD
			AlarmConfigType: string(alarmSetConfigConditionAlgorithmRGBD.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionAlgorithmRGBDBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 急停告警
			AlarmConfigType: string(alarmSetConfigConditionEmergencyStop.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionEmergencyStopBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 急停未复位
			AlarmConfigType: string(alarmSetConfigConditionEmergencyStopResetkey.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionEmergencyStopResetkeyBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 命令暂停
			AlarmConfigType: string(alarmSetConfigConditionReqPausePeople.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionReqPausePeopleBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 识别人体
			AlarmConfigType: string(alarmSetConfigConditionReqPauseAiServerHuman.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionReqPauseAiServerHumanBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 售卖暂停
			AlarmConfigType: string(alarmSetConfigConditionReqPauseAiServerSell.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionReqPauseAiServerSellBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 算法围困
			AlarmConfigType: string(alarmSetConfigConditionSIEGE.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionSIEGEBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 雷达遮挡
			AlarmConfigType: string(alarmSetConfigConditionRadarOcclusion.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionRadarOcclusionBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 强制转动
			AlarmConfigType: string(alarmSetConfigConditionForcedTurn.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionForcedTurnBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 无定位
			AlarmConfigType: string(alarmSetConfigConditionPositionStatic.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionPositionStaticBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 电梯告警
			AlarmConfigType: string(alarmSetConfigConditionElevator.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionElevatorBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 低电告警
			AlarmConfigType: string(alarmSetConfigConditionLowBatt.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionLowBattBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 定位丢失
			AlarmConfigType: string(alarmSetConfigConditionLossOfPositioning.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionLossOfPositioningBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 回充告警
			AlarmConfigType: string(alarmSetConfigConditionBackCharge.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionBackChargeBytes,
		},
		&robotc.AlarmSetConfig_AlarmSetConfigItem{ // 断充告警
			AlarmConfigType: string(alarmSetConfigConditionStopChargingException.ProtoReflect().Descriptor().FullName()),
			BodyContent:     alarmSetConfigConditionStopChargingExceptionBytes,
		},
	)
}

// notifyAlarmContentHandle 告警通知处理
func notifyAlarmContentHandle(ctx context.Context, data []byte) {
	robotID := GetRobotID(ctx)
	alarmNotifyContent := &robotc.NotifyAlarmContent{}
	err := proto.Unmarshal(data, alarmNotifyContent)
	if err != nil {
		return
	}
	// 获取告警额外信息
	duration := getAlarmNotifyInfo(string(alarmNotifyContent.GetAlarmConfigType()), alarmNotifyContent.GetBodyContent())

	// 告警频次限制
	{
		notifyLock := define.RedisAlarmNotifyLock + ":" + robotID + ":" + strconv.Itoa(int(alarmNotifyContent.GetAlaramType()))
		ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
		success, _ := redis.NewDB().SetNX(ctx, notifyLock, time.Now().Unix(), time.Minute*5).Result()
		defer cancel()
		if !success {
			return
		}
	}

	// 获取具体告警记录
	alarmNotifyRecord := models.AlarmNotifyRecord{}
	{
		alarmNotifyRecord.RobotID = robotID
		alarmNotifyRecord.MapName = string(alarmNotifyContent.GetCurrroute())
		alarmNotifyRecord.SetUser = string(alarmNotifyContent.GetAccount().GetUserName())
		alarmNotifyRecord.AlarmSource = int(alarmNotifyContent.GetDadaoCode()) // 新增加的告警来源
		alarmNotifyRecord.AlarmType = int(alarmNotifyContent.GetAlaramType())
		alarmNotifyRecord.MsgContent = string(alarmNotifyContent.GetContent())
		alarmNotifyRecord.PosX = float64(alarmNotifyContent.GetPosx())
		alarmNotifyRecord.PosY = float64(alarmNotifyContent.GetPosy())
		alarmNotifyRecord.PosDirection = float64(alarmNotifyContent.GetPosdirection())
		alarmNotifyRecord.CreatedDate = time.Now().Format("2006-01-02") // 新增加告警日期
		alarmNotifyRecord.CreatedAt = time.Now().Unix() - int64(duration)
	}

	// 保存告警记录
	alarm.AddAlarmNotifyRecord([]models.AlarmNotifyRecord{alarmNotifyRecord})

	// 加入到告警通知消息队列
	{
		type alarmMsgType struct {
			AlarmSource int    `json:"alarm_source"`
			AlarmType   int    `json:"alarm_type"`
			RobotID     string `json:"robot_id"`
			Battery     string `json:"battery"`
			Content     string `json:"content"`
			CreatedAt   int64  `json:"created_at"`
		}
		if alarmNotifyRecord.SetUser == "admin" || alarmNotifyRecord.SetUser == "" {
			var alarmMsg alarmMsgType
			alarmMsg.AlarmType = int(alarmNotifyContent.GetAlaramType())
			alarmMsg.Content = alarmNotifyRecord.MsgContent
			alarmMsg.Battery = "0"
			bat, _ := cache.HGet(define.CacheRobotRTInfo+robotID, "system_battery")
			alarmMsg.Battery, _ = bat.(string)
			alarmMsg.Battery += "%"
			// dataBytes, _ := json.Marshal(alarmMsg)
			// redis.NewDB().LPush(ctx, define.RedisAlarmNotifyList, string(dataBytes))
			// 新的告警推送
			{
				checktime := time.Now().Unix()
				// 缓存告警内容
				alarm_monitor.AlarmMonitor{}.AddMonitor(robotID, alarmMsg.AlarmType, checktime, -1, false, alarmMsg.Content, alarmMsg.Battery)
			}
		}
	}
}
